package com.erlang4j.tests;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;

import junit.framework.Assert;
import junit.framework.TestSuite;

import com.ericsson.otp.erlang.OtpErlangPid;
import com.ericsson.otp.erlang.OtpNode;

public class Erlang4JTestHelper {

	public static TestSuite newSuite(Class<?> clazz) {
		return new TestSuite(clazz.getName());
	}

	public static <T extends Throwable> T assertThrows(Class<T> clazz, String message, Runnable runnable) {
		T t = assertThrows(clazz, runnable);
		Assert.assertEquals(message, t.getMessage());
		return t;
	}

	@SuppressWarnings("unchecked")
	public static <T extends Throwable> T assertThrows(Class<T> clazz, Runnable runnable) {
		try {
			runnable.run();
			throw new AssertionError("Expected " + clazz);
		} catch (AssertionError e) {
			throw e;
		} catch (Throwable t) {
			if (t.getClass() == clazz) {
				return (T) t;
			}
			if (t instanceof RuntimeException)
				throw (RuntimeException) t;
			throw new RuntimeException("Expected " + clazz + " actual " + t.getClass() + " / " + t.getMessage(), t);
		}
	}

	public static void assertAllPropertiesInConstants(String propertiesName, Class<?> constantsFile) {
		try {
			List<String> fieldvalues = new ArrayList<String>();
			for (Field field : constantsFile.getFields())
				if (Modifier.isStatic(field.getModifiers())) {
					Assert.assertTrue(Modifier.isFinal(field.getModifiers()));
					Assert.assertEquals(String.class, field.getType());
					fieldvalues.add((String) field.get(null));
				}
			ResourceBundle bundle = ResourceBundle.getBundle(propertiesName);
			List<String> keys = new ArrayList<String>();
			for (Enumeration<String> e = bundle.getKeys(); e.hasMoreElements();) {
				String bundleValue = e.nextElement();
				keys.add(bundleValue);
				bundle.getString(bundleValue);// asserting it is a string...specifically not an array of strings!
				Assert.assertTrue(bundleValue.trim().length() > 0);
			}
			Set<String> fieldSet = new HashSet<String>(fieldvalues);
			Set<String> keysSet = new HashSet<String>(keys);

			Set<String> fieldsWithoutKeys = new HashSet<String>(fieldSet);
			fieldsWithoutKeys.removeAll(keys);

			Set<String> keysWithoutFields = new HashSet<String>(keys);
			keysWithoutFields.removeAll(fieldSet);

			Assert.assertEquals(fieldsWithoutKeys.toString(), 0, fieldsWithoutKeys.size());
			Assert.assertEquals(keysWithoutFields.toString(), 0, keysWithoutFields.size());

			Assert.assertEquals(fieldSet.size(), fieldvalues.size());
			Assert.assertEquals(keysSet.size(), keysSet.size());
			Assert.assertEquals(fieldvalues.size(), keys.size());

		} catch (Exception e) {
			throw new RuntimeException(e); // this is part of a junit test...all I want to do is see the exception
		}
	}

	public static OtpErlangPid makePid() {
		try {
			return new OtpNode("","").createPid();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
}
